package data.process;

import static common.Common.*;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import data.news.Article;

import prefuse.data.Schema;
import prefuse.data.Table;

import weeny.recycle.Control;
import weeny.recycle.Pair;
import weeny.recycle.Control.LineIterator;
import weeny.util.Entropy;
import weeny.util.Gaussian;

@SuppressWarnings("deprecation")
public class CurveGen {
	
	public static String CURVE_X = "curve_x";
	public static String CURVE_Y = "curve_y";
	public static String ENTROPY = "entropy";
	public static String ID = Article.FLD_ID;
	
	public static Schema CURVE_SCHEMA = new Schema();
	static{
		CURVE_SCHEMA.addColumn(CURVE_X, double.class);
		CURVE_SCHEMA.addColumn(CURVE_Y, double.class);
		CURVE_SCHEMA.addColumn(ENTROPY, double.class);
		CURVE_SCHEMA.addColumn(ID, long.class);
	}
	public static int BIN_NUM = 64;
	
	public static void smooth(Table table, double[] weight, String field){
		List<Double> newYs = new ArrayList<Double>();
		for(int i = 0; i<table.getRowCount(); i++){
			double y = 0;
			double tempTotalWeight = 0;
			for(int j =0; j<weight.length; j++){
				int tmpIndex = i+j-weight.length/2;
				if (tmpIndex>=0 && tmpIndex<table.getRowCount()){
					y+=weight[j]*table.getDouble(tmpIndex, field);
					tempTotalWeight += weight[j];
				}
			}
			newYs.add(y/tempTotalWeight);
		}
		for(int i = 0; i<table.getRowCount(); i++){
			table.setDouble(i, field, newYs.get(i));
		}
	}
	public static void smooth(Table table, double[] weight){
		smooth(table, weight, CURVE_Y);
	}
	private static double[] SMOOTH_WEIGHT = new double[]{0.25,.5, 0.25};//new double[]{0.5,.5,.5,.5,.5,0.5,0.5};
	static{
		Gaussian.MyGaussian gaussian = new Gaussian.MyGaussian(0, 5);
		int arraySize = 9;
		double sum = 0;
		for(int i = -arraySize/2; i<=arraySize/2; i++){
			sum+=gaussian.getValue(i);
		}
		SMOOTH_WEIGHT = new double[arraySize];
		for(int i = 0; i<SMOOTH_WEIGHT.length; i++){
			SMOOTH_WEIGHT[i] = gaussian.getValue(i-arraySize/2)/sum;
		}
	}
	public static Table absoluteEntropyCurve(List<DocInfo> list){
		Table result = CURVE_SCHEMA.instantiate(list.size());
		int idx = 0;
		for (DocInfo docInfo : list) {
			result.set(idx, CURVE_X, idx);
			result.set(idx, CURVE_Y, docInfo.entropy());
			result.setDouble(idx, ENTROPY, docInfo.entropy());
			result.setLong(idx, ID, docInfo.ID);
			idx++;
		}
		smooth(result, SMOOTH_WEIGHT);
		return result;
	}
	public static Table mutualEntropyCurve(List<DocInfo> list){
		return null;
	}
	public static Table conditionalEntropyCurve(List<DocInfo> list){
		return conditionalEntropyCurve(list, SMOOTH_WEIGHT);
	}
	public static Table conditionalEntropyCurve(List<DocInfo> list, double[] weights){
		Table result = CURVE_SCHEMA.instantiate(list.size());
		for(int i = 0; i<list.size(); i++){
			double y = 0;
			double tempTotalWeight = 0;
			for(int j = 0; j<weights.length; j++){
				int tIdx = i+j-weights.length/2;
				if(tIdx>=0 && tIdx<list.size()){
					tempTotalWeight += weights[j];
					y += weights[j] * Entropy.conditionalEntropy(
							list.get(i).freqs, 
							list.get(i).entropy(), 
							list.get(tIdx).freqs, 
							BIN_NUM, BIN_NUM);
				}
			}
			result.setDouble(i, CURVE_X, i);
			result.setDouble(i, CURVE_Y, y/tempTotalWeight);
			result.setDouble(i, ENTROPY, list.get(i).entropy());
			result.setLong(i, ID, list.get(i).ID);
		}
		smooth(result, SMOOTH_WEIGHT);
		return result;
	}
	public static Map<Integer, List<Pair<Integer>>> collectTopMutualDocs(String companyName, int cnt){
		Map<Integer, List<Pair<Integer>>> result = new HashMap<Integer, List<Pair<Integer>>>();
		List<DocInfo> docList = collectInfo(companyName);
		for(int i = 0; i<docList.size(); i++){
			List<Pair<Integer>> tempList = new ArrayList<Pair<Integer>>();
			DocInfo info1 = docList.get(i);
			for(int j = 0; j<docList.size(); j++){
				if (i == j) {
					continue;
				}
				DocInfo info2 = docList.get(j);
				double mutual = Entropy.mutualEntropy(info1.freqs, info2.freqs, BIN_NUM, BIN_NUM);
				Pair<Integer> pair = new Pair<Integer>(info2.ID, mutual);
				tempList.add(pair);
			}
			if(i % 100 == 0){
				System.out.println("procssing document #"+i+"/"+docList.size());
			}
			Collections.sort(tempList, Pair.DESCENDING);
			List<Pair<Integer>> pairList = new ArrayList<Pair<Integer>>();
			for(int j = 0; j<cnt; j++){
				pairList.add(tempList.get(j));
			}
			result.put(info1.ID, pairList);
		}
		return result;
	}
	public static List<DocInfo> collectInfo(String companyName){
		String docFolder = docFolder(companyName);
		List<String> files = Control.searchFilesWithExt("stas", new File(docFolder));
		List<DocInfo> result = new ArrayList<DocInfo>();
//		int totalCount = 200;
		int totalCount = files.size();
		for (int i = 0; i<totalCount; i++) {
			String string = files.get(i);
			DocInfo info = new DocInfo();
			info.date = dateInFileName(string);
			info.ID = idInFileName(string);
			info.freqs = collectFreqs(string);
			result.add(info);
		}
		Collections.sort(result, DocInfo.DATE_ACCENDING);
		return result;
	}
	private static Map<String, Integer> collectFreqs(String fileName){
		Map<String, Integer> result = new HashMap<String, Integer>();
		LineIterator it = new LineIterator(fileName);
		while (it.hasNext()){
			String[] tokens = it.next().split(" ");
			if (isGoodStem(tokens[0])) {
				result.put(tokens[0], Integer.parseInt(tokens[1]));
			}
		}
		return result;
	}
	private static boolean isGoodStem(String stem){
		return true;
	}
	
}
